package com.lagou.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.RetryOneTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;


@Configuration
public class ZKConfig {
    @Value("${config.zookeeper.url}")
    String zkUrl;   // 配置文件读取zk的地址
    @Value("${config.zookeeper.nodename}")
    String nodename;  // 配置所在的节点名

    private Properties properties = new Properties();

    private static Connection connection;

    public String getProperty(String key) {
        String value = properties.getProperty(key);

        if (StringUtils.isEmpty(value)) {
            throw new RuntimeException("配置信息不存在");
        }
        return value;
    }

    @PostConstruct
    public void init() throws SQLException {
        CuratorFramework zkclient = CuratorFrameworkFactory.newClient(zkUrl,
                new RetryOneTime(1000));
        zkclient.start();// 启动Zookeeper的连接

        try {
            // 1. 读取zookeeper数据
            HashMap<String, String> configMap = new HashMap<>();
            List<String> configKeys = zkclient.getChildren().forPath("/" + nodename);
            for (String configKey : configKeys) {
                byte[] data = zkclient.getData().forPath("/" + nodename + "/" + configKey);
                configMap.put(configKey, new String(data));
            }

            // 2. 把数据存储到 properties中
            System.out.println("项目启动从zookeeper配置中心获取到的配置：" + configMap);
            properties.putAll(configMap);
            doConnectionDataSource(properties);
            // 3. 配置发生修改  -->  watch监听机制
            TreeCache treeCache = new TreeCache(zkclient, "/" + nodename);
            treeCache.start(); // 监听整个节点内的数据变化
            treeCache.getListenable().addListener(new TreeCacheListener() {
                @Override
                public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                    // 如果zk中有数据变化，执行相应的代码
                    switch (treeCacheEvent.getType()) {
                        case NODE_UPDATED:
                            System.out.println("数据发生了变化: "+treeCacheEvent.getData());
                            String key = treeCacheEvent.getData().getPath().replace("/"+nodename+"/","");
                            String value = new String(treeCacheEvent.getData().getData());
                            System.out.println("变化后的配置文件key为：" + key +";value为："+ value);
                            properties.setProperty(key, value);
                            doConnectionDataSource(properties);
                            break;
                        default:
                            break;
                    }
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
            connection.close();
        }
    }

    private void doConnectionDataSource(Properties properties) throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl((String) properties.get("jdbcUrl"));
        dataSource.setDriverClassName((String) properties.get("driverClassName"));
        dataSource.setUsername((String) properties.get("username"));
        dataSource.setPassword((String) properties.get("password"));
        dataSource.setInitialSize(Integer.parseInt((String)properties.get("initialSize")));
        dataSource.restart();
        System.out.println(">>>>>开始连接数据库,连接个数为：" + dataSource.getInitialSize());
    }
}
